<?php

namespace app\admin\model\shop\goods;

use app\shop\library\ShopHelper;
use ba\Exception;
use think\helper\Arr;
use think\Model;
use think\model\concern\SoftDelete;
use think\model\relation\HasMany;
use Throwable;

/**
 * Goods
 */
class Goods extends Model
{
    use SoftDelete;

    protected $defaultSoftDelete = 0;

    // 表名
    protected $name = 'shop_goods';

    // 自动写入时间戳字段
    protected $autoWriteTimestamp = true;

    protected $jsonAssoc = true;

    protected $append = ['spec_data'];

    // protected $hidden = ['spec_list'];

    public function sku(): HasMany
    {
        return $this->hasMany(GoodsSku::class, 'goods_id', 'id');
    }

    public function setParamsAttr($value): string
    {
        return ShopHelper::array_to_json($value);
    }

    public function getParamsAttr($value): array
    {
        return ShopHelper::json_to_array($value);
    }

    public function getImagesAttr($value): array
    {
        if ($value === '' || $value === null) return [];
        if (!is_array($value)) {
            return explode(',', $value);
        }
        return $value;
    }

    public function setImagesAttr($value): string
    {
        return is_array($value) ? implode(',', $value) : $value;
    }

    public function getDetailImagesAttr($value): array
    {
        if ($value === '' || $value === null) return [];
        if (!is_array($value)) {
            return explode(',', $value);
        }
        return $value;
    }

    public function setDetailImagesAttr($value): string
    {
        return is_array($value) ? implode(',', $value) : $value;
    }

    public function getDescAttr($value): string
    {
        return !$value ? '' : htmlspecialchars_decode($value);
    }

    //存储分类ID
    public function setClassifyIDAttr($value): string
    {
        return implode(',', $value);
    }

    //获取分类ID
    public function getClassifyIDAttr($value): array|bool
    {
        return explode(',', $value);
    }

    public function getSpecListAttr($value): array
    {
        if (is_array($value)) {
            return $value;
        }

        return ShopHelper::json_to_array($value);
    }


    public function getSpecDataAttr($value, $data): array
    {
        if (!Arr::has($data, 'spec_list')) {
            return [];
        }

        $skus = $this->sku->each(function ($sku) {
            $sku->price        = floatval($sku->price);
            $sku->origin_price = floatval($sku->origin_price);
        });

        return [
            'specList' => ShopHelper::json_to_array($data['spec_list']),
            'skuList'  => $skus,
        ];
    }

    public function getServiceIdAttr($value): array|bool
    {
        if ($value) {
            return explode(',', $value);
        }

        return $value;
    }

    public function setServiceIdAttr($value): string
    {
        if (is_array($value)) {
            return implode(',', $value);
        }

        return $value;
    }

    //插入后事件
    protected static function onAfterInsert($model): void
    {
        if ($model->weigh == 0) {
            $pk = $model->getPk();
            if (strlen($model[$pk]) >= 19) {
                $model->where($pk, $model[$pk])->update(['weigh' => $model->count()]);
            } else {
                $model->where($pk, $model[$pk])->update(['weigh' => $model[$pk]]);
            }
        }
    }

    /**
     * 写入后事件
     * @param Model $model
     * @throws Exception
     */
    public static function onAfterWrite(Model $model): void
    {
        $specData = request()->post('spec_data');

        if ($specData) {
            $model->handleSpecData($model, $specData);

            $model->where('id', $model->getData('id'))->update([
                'spec_list' => ShopHelper::array_to_json($specData['specList'])
            ]);

            $model->summarySkuInfo($model);
        }
    }

    /**
     * 删除后事件
     * @param Model $model
     * @return void
     */
    public static function onAfterDelete(Model $model): void
    {
        $model->sku()->delete();
    }

    /**
     * 处理规格数据
     * @param       $model
     * @param array $specData
     * @return void
     * @throws Exception
     */
    public function handleSpecData($model, array $specData): void
    {
        $specList = $specData['specList'] ?? [];
        $skuList  = $specData['skuList'] ?? [];
        if (!$specList || !$skuList) {
            throw new Exception(__('Incomplete specification data'));
        }

        $this->validateSpecData($specList, $skuList);
        try {
            $this->handleSkuInfo($model->getData('id'), $skuList);
        } catch (Throwable $e) {
            throw new Exception($e->getMessage());
        }
    }

    /**
     * 校验规格数据
     * @param array $specList
     * @param array $skuList
     * @return void
     * @throws Exception
     */
    private function validateSpecData(array $specList, array $skuList): void
    {
        $attrNames = array_column($specList, 'name');
        if (count($attrNames) !== count(array_unique($attrNames))) {
            throw new Exception(__('The specification name cannot be duplicated'));
        }

        $attrValues = array_column($specList, 'value');

        $attrValues = array_reduce($attrValues, 'array_merge', []);

        if (count($attrValues) !== count(array_unique($attrValues))) {
            throw new Exception(__('The specification value cannot be repeated'));
        }

        $generateSpecs = $this->generateProductSpecs($specList);
        $specs         = array_column($skuList, 'spec');
        foreach ($specs as $spec) {
            if (!in_array($spec, $generateSpecs)) {
                throw new Exception(__('The specification attributes do not match the generated SKU'));
            }
        }
    }

    /**
     * 生成商品规格
     * @param array $specList
     * @return array
     */
    private function generateProductSpecs(array $specList): array
    {
        $result = [[]];

        foreach ($specList as $spec) {
            $tmp = [];
            foreach ($result as $res) {
                foreach ($spec['value'] as $value) {
                    $tmp[] = array_merge($res, [$spec['name'] . ':' . $value]);
                }
            }
            $result = $tmp;
        }

        return array_map(function ($item) {
            return implode(';', $item);
        }, $result);
    }

    /**
     * 处理规格SKU信息
     * @param int   $goodsId 商品ID
     * @param array $skuList 规格列表
     */
    private function handleSkuInfo(int $goodsId, array $skuList): void
    {
        $existIds = [];
        foreach ($skuList as $sku) {
            if (Arr::has($sku, 'id')) {
                GoodsSku::update($sku, ['id' => $sku['id']]);
                $existIds[] = $sku['id'];
            } else {
                $specData   = array_merge($sku, ['goods_id' => $goodsId, 'spec' => $sku['spec']]);
                $spec       = GoodsSku::create($specData);
                $existIds[] = $spec->id;
            }
        }

        GoodsSku::destroy(function ($query) use ($goodsId, $existIds) {
            $query->where('goods_id', $goodsId)->whereNotIn('id', $existIds);
        });

    }

    public function summarySkuInfo($model): void
    {
        $skuInfo = $model->sku->toArray();

        $prices       = array_column($skuInfo, 'price');
        $originPrices = array_column($skuInfo, 'origin_price');

        $updateData = [
            'min_price'        => $prices ? min($prices) : 0,
            'max_price'        => $prices ? max($prices) : 0,
            'min_origin_price' => $originPrices ? min($originPrices) : 0,
            'max_origin_price' => $originPrices ? max($originPrices) : 0,
            'total_stock'      => array_sum(array_column($skuInfo, 'stock')),
            'sales_real'       => array_sum(array_column($skuInfo, 'sales'))
        ];

        $model->where('id', $model->getData('id'))->update($updateData);
    }
}